//********************************************************************
// 
//  file:  Session.cs
// 
//  (C) Copyright 2010, Diomede Corporation
//  All rights reserved
// 
//  Use, modification, and distribution is subject to   
//  the New BSD License (See accompanying file license.txt).
// 
//********************************************************************

using System;
using System.Collections.Generic;
using data.diomedestorage.com;

namespace Diomede.SDK
{

    #region Interfaces
    /// <summary>
    /// Provide the interface for handling Diomede Service Session.  This will allow the developer to initiate all Diomede Storage API interactions.
    /// </summary>
    public interface ISession
    {
        /// <summary>
        /// Create new Diomede Service Session.
        /// </summary>
        /// <param name="username">Registered Diomede account username.</param>
        /// <param name="password">Account password</param>
        /// <returns>Will return Session Execution Result, see <see cref="ISessionExecResult"/>.</returns>
        /// <example>
        /// Below are the examples on creating new Session, through login command.
        /// <code>
        /// ISession session = new Session();
        /// ISessionExecResult result = session.Login("username", "password");
        /// if (result.Status == ExecutionResults.Success)
        ///     Console.WriteLine(string.Format("Login successful, your session token is {0}", result.Token));
        /// else
        ///    Console.WriteLine(string.Format("Login failed, error: {0}", result.Message));
        /// </code>
        /// <code lang="VB.NET">
        /// Dim session As ISession = New Session()
        /// Dim result As ISessionExecResult
        /// result = session.Login("username", "password")
        /// If (result.Status = Enums.ExecutionResults.Success) Then
        ///     Console.WriteLine(String.Format("Login successful, your session token is {0}", result.Token))
        /// Else
        ///     Console.WriteLine(String.Format("Login failed, error: {0}", result.Message))
        /// End If
        /// </code>
        /// </example>
        ISessionExecResult Login(string username, string password);
        /// <summary>
        /// Destroy the current Diomede session.
        /// </summary>
        /// <returns>Will return Session Execution Result, see <see cref="ISessionExecResult"/>.</returns>
        ISessionExecResult Logout();
        /// <summary>
        /// Change the password.
        /// </summary>
        /// <param name="currentPassword">The current password.</param>
        /// <param name="newPassword">The new password</param>
        /// <returns>Will return Session Execution Result, see <see cref="ISessionExecResult"/>.</returns>
        ISessionExecResult ChangePassword(string currentPassword, string newPassword);
        /// <summary>
        /// Will hold the Session Token
        /// </summary>
        string Token { get;set;}
        /// <summary>
        /// If the session is successfully created, this will hold Diomede service client object.
        /// </summary>
        DiomedeStorageClient ServiceClient { get;}
        /// <summary>
        /// If the session is successfully created, this will hold Diomede transfer client object.
        /// </summary>
        DiomedeStorageTransferClient TransferClient { get;}

        string ServiceUrl { get; set;}

        string TransferUrl { get; set;}
    }

    /// <summary>
    /// Provides the generic interface for execution results. 
    /// </summary>
    public interface IExecResult
    {
        /// <summary>
        /// Result status for the execution of a session methods,
        /// see <see cref="Enums.ExecutionResults"/> for more information.
        /// </summary>
        Enums.ExecutionResults Status { get; set;}
        /// <summary>
        /// Result message for the execution of a session methods
        /// </summary>
        string Message { get; set;}
    }

    /// <summary>
    /// Provides the interface for all Session execution results.
    /// </summary>
    public interface ISessionExecResult : IExecResult
    {
        /// <summary>
        /// Current session execution token.
        /// </summary>
        string Token { get; set;}

        /// <summary>
        /// Account profile, will have value only if the method executed is involving account profiles.
        /// </summary>
        UserInfo UserInfo { get; set;}
    }

    /// <summary>
    /// Provides the interface for all Email execution results.
    /// </summary>
    public interface IEmailsExecResult :  IExecResult
    {
        /// <summary>
        ///  Holders of returned emails.
        /// </summary>
        List<string> Emails
        {
            get;
            set;
        }
    }

    #endregion

    #region Implementation

    /// <summary>
    /// Session Class implementation, please see <see cref="ISession"/>
    /// </summary>
    public partial class Session : ISession
    {
        #region Privates
        DiomedeStorageClient service;
        DiomedeStorageTransferClient transfer;

        #endregion

        #region Constructors
        /// <summary>
        /// Will create new instance of Session object, see <see cref="ISession"/>.
        /// </summary>
        public Session()
        {
            if (string.IsNullOrEmpty(this.serviceUrl))
            {
                service = new DiomedeStorageClient();
            }
            else
            {
                service = new DiomedeStorageClient("BasicHttpBinding_IDiomedeStorage", serviceUrl);
            }

            if (string.IsNullOrEmpty(this.transferUrl))
            {
                transfer = new DiomedeStorageTransferClient();
            }
            else
            {
                transfer = new DiomedeStorageTransferClient("BasicHttpBinding_IDiomedeStorageTransfer", transferUrl);
            }
        }

        public Session(bool overRide, string serviceUrl, string transferUrl)
        {
            this.serviceUrl = serviceUrl;
            this.transferUrl = transferUrl;

            service = new DiomedeStorageClient("BasicHttpBinding_IDiomedeStorage", this.serviceUrl);
            transfer = new DiomedeStorageTransferClient("BasicHttpBinding_IDiomedeStorageTransfer", this.transferUrl);
        }

        /// <summary>
        /// Will create new Diomede Session, see <see cref="ISession"/> 
        /// </summary>
        /// <param name="username">Registered Diomede account username.</param>
        /// <param name="password">Account password</param>
        public Session(string username, string password)
        {
            (this as ISession).Login(username, password);
        }

        #endregion

        #region ISession Members

        /// <summary>
        /// ISession.Login implementation, see <see cref="ISession.Login"/> for more information.
        /// </summary>
        /// <param name="username">Registered Diomede account username.</param>
        /// <param name="password">Accont password</param>
        /// <returns>Will return Status = Success if command is successful.</returns>
        ISessionExecResult ISession.Login(string username, string password)
        {
            try
            {
                if (service == null || service.State == System.ServiceModel.CommunicationState.Closed)
                    service = new DiomedeStorageClient();

                token = service.Login(username, password);
                return new SessionExecResult(token);
            }
            catch (Exception ex)
            {
                return new SessionExecResult(ex);
            }

        }

        /// <summary>
        /// ISession.Logout implementation, see <see cref="ISession.Logout"/> for more information.
        /// </summary>
        /// <returns>Will return Status = Success if command is successful.</returns>
        ISessionExecResult ISession.Logout()
        {
            try
            {
                if (service == null)
                    return new SessionExecResult(Enums.ExecutionResults.Failed, "No active session.");

                service.Logout(token);

                (this as ISession).Token = string.Empty;

                service.Close();

                return new SessionExecResult(Diomede.SDK.Enums.ExecutionResults.Success, "Logout successful.");

            }
            catch (Exception ex)
            {
                return new SessionExecResult(ex);
            }
        }

        /// <summary>
        /// ISession.ChangePassword implementation, see <see cref="ISession.ChangePassword"/> for more information.
        /// </summary>
        /// <param name="currentPassword">Current password.</param>
        /// <param name="newPassword">New password.</param>
        /// <returns></returns>
        ISessionExecResult ISession.ChangePassword(string currentPassword, string newPassword)
        {
            try
            {
                if (service == null)
                    return new SessionExecResult(Enums.ExecutionResults.Failed, "No active session.");

                service.ChangePassword(token, currentPassword, newPassword);

                return new SessionExecResult(Diomede.SDK.Enums.ExecutionResults.Success, "Password successfully changed.");

            }
            catch (Exception ex)
            {
                return new SessionExecResult(ex);
            }
        }

        string token;
        /// <summary>
        /// ISession.Token property implementation, see <see cref="ISession.Token"/> for more information.
        /// </summary>
        string ISession.Token
        {
            get
            {
                return token;
            }
            set
            {
                token = value;
            }
        }

        /// <summary>
        /// ISession.ServiceClient property implementation, see <see cref="ISession.ServiceClient"/> for more information.
        /// </summary>
        DiomedeStorageClient ISession.ServiceClient
        {
            get { return service; }
        }

        /// <summary>
        /// ISession.TransferClient property implmentation, see <see cref="ISession.TransferClient"/> for more information.
        /// </summary>
        DiomedeStorageTransferClient ISession.TransferClient
        {
            get { return transfer; }
        }

        #endregion

        #region ISession Members

        string serviceUrl;
        string ISession.ServiceUrl
        {
            get
            {
                return serviceUrl;
            }
            set
            {
                serviceUrl = value;
            }
        }

        string transferUrl;
        string ISession.TransferUrl
        {
            get
            {
                return transferUrl;
            }
            set
            {
                transferUrl = value;
            }
        }

        #endregion
    }

    /// <summary>
    /// ISessionExecResult implementation, see <see cref="ISessionExecResult"/> for more information.
    /// </summary>
    public class SessionExecResult :  ISessionExecResult
    {
        /// <summary>
        /// Create new instance of SessionExecResult
        /// </summary>
        public SessionExecResult()
        {
        }

        /// <summary>
        /// Create new instance of SessionExecResult, with sessionToken  as parameter.
        /// <br/>
        /// Using this constructor will automatically set the Status = <see cref="Enums.ExecutionResults.Success"/>, and Message to "Session created successfully."
        /// </summary>
        /// <param name="sessionToken">New session token</param>
        public SessionExecResult(string sessionToken)
        {
            ISessionExecResult t = this;
            t.Token = sessionToken;
            t.Message = "Session created successfully.";
            t.Status = Enums.ExecutionResults.Success;
        }
        /// <summary>
        /// Create new instance of SessionExecResult, with <see cref="UserInfo"/> as parameter.
        /// <br/>
        /// Using this constructor will automatically set the Status = <see cref="Enums.ExecutionResults.Success">ExecutionResults.Success</see>.
        /// </summary>
        /// <param name="profile">UserInfo</param>
        public SessionExecResult(UserInfo profile)
        {
            ISessionExecResult t = this;
            t.Status = Diomede.SDK.Enums.ExecutionResults.Success;
            t.Message = "";
            t.UserInfo = profile;
        }

        /// <summary>
        /// Create new instance of SessionExecResult
        /// </summary>
        /// <param name="status"><see cref="Enums.ExecutionResults"/> for the new instance.</param>
        /// <param name="message">Message</param>
        public SessionExecResult(Enums.ExecutionResults status, string message)
        {
            ISessionExecResult t = this;
            t.Status = status;
            t.Message = message;
        }

        /// <summary>
        /// Create new instance of SessionExecResult, with <see cref="Exception"/> as parameters.
        /// <br/>
        /// Using this constructor, will automatically set the Status = <see cref="Enums.ExecutionResults.Failed">ExecutionResults.Failed</see> and Message = <see cref="Exception.Message">Exception.Message</see>.
        /// </summary>
        /// <param name="ex">Exception</param>
        public SessionExecResult(Exception ex)
        {
            ISessionExecResult t = this;
            t.Message = ex.Message;
            t.Status = Enums.ExecutionResults.Failed;
        }

        #region ISessionExecResult Members



        string token;
        /// <summary>
        /// ISessionExecResult.Token implementation, see <see cref="ISessionExecResult.Token">ISessionExecResult.Token</see> for more information.
        /// </summary>
        string ISessionExecResult.Token
        {
            get
            {
                return token;
            }
            set
            {
                token = value;
            }
        }

        UserInfo profile;
        /// <summary>
        /// ISessionExecResult.Profile implementation, see <see cref="ISessionExecResult.UserInfo">ISessionExecResult.UserInfo</see> for more information.
        /// </summary>
        UserInfo ISessionExecResult.UserInfo
        {
            get { return profile; }
            set { profile = value; }
        }

        #endregion

        #region IExecResult Members
        Enums.ExecutionResults status;
        /// <summary>
        /// IExecResult.Status implementation, see <see cref="IExecResult.Status">IExecResult.Status</see> for more information.
        /// </summary>
        Enums.ExecutionResults IExecResult.Status
        {
            get
            {
                return status;
            }
            set
            {
                status = value;
            }
        }

        string message;
        /// <summary>
        /// IExecResult.Message implementation, see <see cref="IExecResult.Message">IExecResult.Message</see> for more information.
        /// </summary>
        string IExecResult.Message
        {
            get
            {
                return message;
            }
            set
            {
                message = value;
            }
        }

        #endregion
    }

    /// <summary>
    /// Object that will be returned on email related executions.
    /// </summary>
    public class EmailsExecResult : IEmailsExecResult
    {
        /// <summary>
        /// Create new instance of SessionExecResult.
        /// </summary>
        public EmailsExecResult()
            : base()
        {
        }
        /// <summary>
        /// Create new instance of SessionExecResult, with an Exception object  as parameter.
        /// </summary>
        /// <param name="ex">Exception.</param>
        public EmailsExecResult(Exception ex)
        {
            IEmailsExecResult t = this;
            t.Message = ex.Message;
            t.Status = Enums.ExecutionResults.Failed;
        }
        /// <summary>
        /// Create new instance of SessionExecResult, with status, message and an array of email address  as parameters.
        /// </summary>
        /// <param name="status">Returned status.</param>
        /// <param name="message">Returned message.</param>
        /// <param name="emails">Returned emails.</param>
        public EmailsExecResult(Enums.ExecutionResults status, string message, string[] emails)
        {
            IEmailsExecResult t = this;
            t.Status = status;
            t.Message = message;
            if (emails != null)
            {
                this.emails = new List<string>();
                this.emails.AddRange(emails);
            }
        }

        private List<string> emails;

        /// <summary>
        ///  Holders of returned emails.
        /// </summary>
        List<string> IEmailsExecResult.Emails
        {
            get { return emails; }
            set { emails = value; }
        }

        #region IExecResult Members

        Enums.ExecutionResults status;
        /// <summary>
        /// IExecResult.Status implementation, see <see cref="IExecResult.Status">IExecResult.Status</see> for more information.
        /// </summary>
        Enums.ExecutionResults IExecResult.Status
        {
            get
            {
                return status;
            }
            set
            {
                status = value;
            }
        }

        string message;
        /// <summary>
        /// IExecResult.Message implementation, see <see cref="IExecResult.Message">IExecResult.Message</see> for more information.
        /// </summary>
        string IExecResult.Message
        {
            get
            {
                return message;
            }
            set
            {
                message = value;
            }
        }

        #endregion

    }

    #endregion
}